package com.hcj.demo.controller;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.hcj.demo.vo.ProcessVo;
import com.hcj.demo.vo.TaskCommentVo;
import com.hcj.demo.vo.TaskHistoryVo;
import com.hcj.demo.vo.TaskVo;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.CommentEntity;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.form.api.*;
import org.flowable.form.api.FormService;
import org.flowable.form.engine.impl.persistence.entity.FormDeploymentEntityImpl;
import org.flowable.form.engine.impl.persistence.entity.FormResourceEntity;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

/**
 * @author huangcj
 * @date 2020-09-29 10:30
 */
@Slf4j
@RestController
@RequestMapping("common")
public class CommonController {

    private static final Gson gson = new GsonBuilder()
            //序列化null
            .serializeNulls()
            // 设置日期时间格式，另有2个重载方法，在序列化和反序化时均生效
            .setDateFormat("yyyy-MM-dd HH:mm:ss")
            // 禁此序列化内部类
            .disableInnerClassSerialization()
            //禁止转义html标签
            .disableHtmlEscaping()
            //格式化输出
            .setPrettyPrinting()
            .create();
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private HistoryService historyService;
    @Resource
    private ProcessEngine processEngine;
    @Autowired
    private FormRepositoryService formRepositoryService;
    @Autowired
    private FormService formService;


    /**
     * 清空流程实例
     */
    @PostMapping("cleanProcessInstance")
    public String cleanProcessInstance() {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey("Expense").list();
        if (Objects.nonNull(list) && !list.isEmpty()) {
            list.stream().forEach(x -> {
                // 清空任务
                runtimeService.deleteProcessInstance(x.getProcessInstanceId(), "清空流程：" + x.getProcessDefinitionKey());
                log.info("清理流程 ===> id:{} \t key:{}", x.getProcessInstanceId(), x.getProcessDefinitionKey());
            });
        }
        return "清理任务";
    }

    /**
     * 删除流程实例
     */
    @PostMapping("deleteProcessInstanceById")
    public String deleteProcessInstanceById(String processInstanceId) {
        runtimeService.deleteProcessInstance(processInstanceId, "删除流程实例的理由：" + processInstanceId);
        return "删除流程实例：成功" + processInstanceId;
    }

    /**
     * 挂起流程实例
     *
     * @param processInstanceId 当前流程实例id
     */
    @PostMapping("hangUpProcessInstanceById")
    public String handUpProcessInstance(String processInstanceId) {
        runtimeService.suspendProcessInstanceById(processInstanceId);
        return "挂起流程成功...";
    }

    /**
     * 唤起流程实例
     *
     * @param processInstanceId 当前流程实例id
     */
    @PostMapping("recoverProcessInstanceById")
    public String recoverProcessInstance(String processInstanceId) {
        runtimeService.activateProcessInstanceById(processInstanceId);
        return "唤起流程实例成功...";
    }

    /**
     * 判断传入流程实例在运行中是否存在
     *
     * @param processInstanceId
     * @return
     */
    @GetMapping("isExist/running")
    public Boolean isExistProcIntRunning(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance == null) {
            return false;
        }
        return true;
    }

    /**
     * 判断流程实例在历史记录中是否存在
     *
     * @param processInstanceId
     * @return
     */
    @GetMapping("isExist/history")
    public Boolean isExistProcInHistory(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (historicProcessInstance == null) {
            return false;
        }
        return true;
    }


    /**
     * 我发起的流程实例列表
     *
     * @param userId
     * @return 流程实例列表
     */
    @GetMapping("myTasks")
    public List<HistoricProcessInstance> getMyStartProcint(String userId) {
        List<HistoricProcessInstance> list = historyService
                .createHistoricProcessInstanceQuery()
                .startedBy(userId)
                .orderByProcessInstanceStartTime()
                .asc()
                .list();
        return list;
    }


    /**
     * 某人的审批任务列表
     */
    @GetMapping("/listTaskByUserId")
    public Object listTaskByUserId(@RequestParam String userId) {
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
        List<TaskVo> list = new ArrayList<>();
//        Task task = tasks.get(0);
//        if(task != null){
//            log.info("task.getProcessVariables() = {}", task.getProcessVariables());
//            String processInstanceId = task.getProcessInstanceId();
//            List<ProcessInstance> processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).list();
//            if(processInstance != null){
//                log.info("processInstance.getProcessVariables() = {}", processInstance.get(0).getProcessVariables());
//            }
//        }
        tasks.forEach(x -> list.add(new TaskVo(x.getId(), x.getName(), x.getCreateTime())));
        log.info("获取{}的审批列表 = {}", userId, list);
        //log.info("gson.toJson===> {}", gson.toJson(list));
        return list;
    }

    /**
     * 获取指定用户组流程任务列表
     *
     * @param groupName
     * @return
     */
    @GetMapping("listTaskByGroupName")
    public Object listTaskByGroupName(String groupName) {
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup(groupName).list();
        return tasks;
    }

    /**
     * 查看整个流程历史记录
     *
     * @param processInstanceId
     * @return
     */
    @GetMapping("listHistory")
    public Object getHistoryList(String processInstanceId) {
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();

        return historicActivityInstances;
    }

    /**
     * 查看流程中任务历史记录
     *
     * @param processInstanceId
     * @return
     */
    @GetMapping("listTaskHistory")
    public Object getTaskHistoryList(String processInstanceId) {
        Set<String> activityTypes = new HashSet<>();
        // 只显示一下事件的历史
        activityTypes.add("startEvent");
        activityTypes.add("endEvent");
        activityTypes.add("userTask");
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .activityTypes(activityTypes)
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();


        // 转换显示结果
        List<TaskHistoryVo> list = new ArrayList<>();
        historicActivityInstances.stream().forEach(x -> {
            List<Comment> taskComments = taskService.getTaskComments(x.getTaskId(), CommentEntity.TYPE_COMMENT);
            List<TaskCommentVo> taskCommentVos = new ArrayList<>();
            if (taskComments != null && !taskComments.isEmpty()) {
                taskComments.stream().forEach(y -> {
                    taskCommentVos.add(new TaskCommentVo(y.getId(), y.getFullMessage(), y.getTime()));
                });
            }
            list.add(new TaskHistoryVo(x.getTaskId(), x.getActivityName(), x.getStartTime(), x.getEndTime(), x.getAssignee(), x.getDurationInMillis(), taskCommentVos));
        });

        return list;
    }

    /**
     * 正在运行的审批实例列表
     */
    @GetMapping("/listActiveProcessInstance")
    public String listActiveProcessInstance() {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().active().list();
        // 组装显示数据
        List<ProcessVo> listVo = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            list.stream().forEach(x -> {
                ProcessVo processVo = new ProcessVo()
                        .setId(x.getId())
                        .setProcessDefinitionId(x.getProcessDefinitionId())
                        .setProcessDefinitionKey(x.getProcessDefinitionKey())
                        .setProcessDefinitionName(x.getProcessDefinitionName())
                        .setStartTime(x.getStartTime());
                listVo.add(processVo);
            });
        }
        return gson.toJson(listVo);
    }


    /**
     * 生成流程图
     *
     * @param processId 流程ID
     */
    @GetMapping("genProcessDiagramByProcessId")
    public void genProcessDiagramByProcessId(HttpServletResponse httpServletResponse, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

        // 流程走完的不显示图
        if (pi == null) {
            return;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        // 使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        // 得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        // 获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(
                bpmnModel, "png",
                activityIds, flows,
                engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(),
                engconf.getClassLoader(), 1.0D, true);

        int len = 0;
        byte[] buf = new byte[1024];
        try (OutputStream out = httpServletResponse.getOutputStream()) {
            while ((len = in.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
        } finally {
            if (in != null) {
                in.close();
            }
        }
    }


    /**
     * 获取表单定义信息
     *
     * @param formName
     * @param formKey
     */
    @GetMapping("getFormDefinitionInfo")
    public FormDefinition getFormDefinitionInfo(@RequestParam String formName, @RequestParam String formKey) {
        FormDefinitionQuery formDefinitionQuery = formRepositoryService.createFormDefinitionQuery();
        if (formName != null && !"".equals(formName)) {
            formDefinitionQuery.formNameLike(formName);
        }
        if (formKey != null && !"".equals(formKey)) {
            formDefinitionQuery.formDefinitionKey(formKey);
        }
        FormDefinition formDefinition = formDefinitionQuery.latestVersion().singleResult();
        return formDefinition;
    }

    /**
     * 获取表单定义信息
     *
     * @param deploymentId
     */
    @GetMapping("getFormInfoByDeploymentId")
    public FormDefinition getFormInfoByDeploymentId(@RequestParam String deploymentId) {
        FormDefinition formDefinition = formRepositoryService.createFormDefinitionQuery()
                .deploymentId(deploymentId)
                .singleResult();
        return formDefinition;
    }


    /**
     * 获取表单部署信息
     *
     * @param deploymentId
     */
    @GetMapping("getFormDeployInfoByDeploymentId")
    public FormDeployment getFormDeployInfoByDeploymentId(@RequestParam String deploymentId) {
        FormDeployment formDeployment = formRepositoryService.createDeploymentQuery()
                .deploymentId(deploymentId)
                .singleResult();
        return formDeployment;
    }

    /**
     * 获取表单详细信息
     *
     * @param formKey
     */
    @GetMapping("getFormInfo")
    public Object getFormInfo(@RequestParam String formKey) {
        FormInfo formInfo = formRepositoryService.getFormModelByKey(formKey);
        return formInfo;
    }


    /**
     * 手动部署表单
     */
    @GetMapping("deployForm")
    public Object deployForm() {
        String form2Str = "{\n" +
                "  \"key\": \"form3\",\n" +
                "  \"name\": \"My third form\",\n" +
                "  \"fields\": [\n" +
                "    {\n" +
                "      \"id\": \"input\",\n" +
                "      \"name\": \"Input\",\n" +
                "      \"type\": \"text\",\n" +
                "      \"required\": false,\n" +
                "      \"placeholder\": \"请输入一个值\"\n" +
                "    }\n" +
                "  ],\n" +
                "  \"outcomes\": [\n" +
                "    {\n" +
                "      \"id\": \"null\",\n" +
                "      \"name\": \"驳回\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"id\": \"null\",\n" +
                "      \"name\": \"通过\"\n" +
                "    }\n" +
                "  ]\n" +
                "}";
        FormDeployment deploy = formRepositoryService.createDeployment()
                .name("手动部署一个表单")
                //.addClasspathResource("selfDeployForm/test2.form")
                .addFormDefinition("my second form", form2Str)
                .deploy();

        if (deploy instanceof FormDeploymentEntityImpl) {
            Map<String, FormResourceEntity> resources = ((FormDeploymentEntityImpl) deploy).getResources();
            resources.forEach((k, v) -> {
                log.info("key = {}, value = {}", k, new String(v.getBytes()));
            });
        }

        return deploy;
    }
}
